package com.wskj.pay.impl;


import com.alibaba.fastjson.JSON;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.wskj.common.core.domain.AjaxResult;
import com.wskj.common.core.domain.entity.SysUser;
import com.wskj.common.utils.common.AmountCalUtils;
import com.wskj.common.utils.common.AssertUtils;
import com.wskj.common.utils.common.MD5Utils;
import com.wskj.common.utils.wx.WXConfigUtil;
import com.wskj.config.properties.WXConfig;
import com.wskj.pay.IWxService;
import com.wskj.system.domain.SysCommon;
import com.wskj.system.service.ISysCommonService;
import com.wskj.system.service.ISysUserService;
import jodd.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author fang
 * @date 2020/2/26
 */
@Slf4j
@AllArgsConstructor
@Service
public class WxServiceImpl implements IWxService {
    private static final String SPBILL_CREATE_IP = "127.0.0.1";
    private static final String TRADE_TYPE_APP = "APP";
    private static final String TRADE_TYPE_NATIVE = "NATIVE";
    private static final String TRADE_TYPE_JSAPI = "JSAPI";
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private final ISysCommonService iSysCommonService;
    private final ISysUserService iSysUserService;

    @Override
    public AjaxResult pay(Double moneys, Integer classify, Long userId, String outTradeNo,String attach){
        try{
            // 服务域名配置
            SysCommon oneu = iSysCommonService.getById(1000048L);
            String url;
            if (classify == 3) {
                // 小程序 公众号支付 回调地址
                url = oneu.getCommonValue() + "/stage-api/api/wx/pay/notify/jsapi";
            } else if (classify == 2) {
                // 二维码支付
                url = oneu.getCommonValue() + "/stage-api/api/wx/pay/notify/mp";
            } else {
                // app
                url = oneu.getCommonValue() + "/stage-api/api/wx/pay/notify";
            }
            String currentTimeMillis = (System.currentTimeMillis() / 1000) + "";
            // 后台服务名称
            SysCommon one = iSysCommonService.getById(1000054L);
            log.info("回调地址：" + url);
            Double mul = AmountCalUtils.mul(moneys, 100);
            String money = String.valueOf(mul.intValue());
            String generateNonceStr = WXPayUtil.generateNonceStr();
            WXConfig config = new WXConfig();
            if (classify == 1) {
                // 微信APP APPID
                config.setAppId(iSysCommonService.getById(1000004L).getCommonValue());
            } else if (classify == 2) {
                // 微信公众号 APPID
                config.setAppId(iSysCommonService.getById(1000055L).getCommonValue());
            } else {
                // 微信小程序 APPID
                config.setAppId(iSysCommonService.getById(1000002L).getCommonValue());
            }
            // 微信商户key
            config.setKey(iSysCommonService.getById(1000006L).getCommonValue());
            // 微信商户号mchId
            config.setMchId(iSysCommonService.getById(1000007L).getCommonValue());
            WXPay wxpay = new WXPay(config);
            Map<String, String> data = new HashMap<>();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("nonce_str", generateNonceStr);
            String body = one.getCommonValue();
            data.put("body", body);
            // 生成商户订单号，不可重复
            data.put("out_trade_no", outTradeNo);
            data.put("total_fee", money);
            // 自己的服务器IP地址
            data.put("spbill_create_ip", SPBILL_CREATE_IP);
            // 异步通知地址（请注意必须是外网）
            data.put("notify_url", url);
            // 交易类型
            data.put("trade_type", classify == 1 ? TRADE_TYPE_APP : TRADE_TYPE_JSAPI);
            //附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据
            data.put("attach", attach);
            data.put("sign", WXPayUtil.generateSignature(data, config.getKey(),
                    WXPayConstants.SignType.MD5));
            if (classify == 3 || classify == 2) {
                SysUser dbSysUser = iSysUserService.getById(userId);
                if (classify == 3) {
                    if (StringUtil.isNotBlank(dbSysUser.getWxUid())) {
                        data.put("openid", dbSysUser.getWxUid());
                    }
                } else {
                    data.put("openid", dbSysUser.getWxUid());
                }
            }
            // 使用官方API请求预付订单
            Map<String, String> response = wxpay.unifiedOrder(data);
            for (String key : response.keySet()) {
                log.info("微信支付订单微信返回参数：keys:" + key + "    value:" + response.get(key).toString());
            }
            if ("SUCCESS".equals(response.get("return_code")) && "SUCCESS".equals(response.get("result_code"))) {
                // 主要返回以下5个参数
                if (classify == 1) {
                    Map<String, String> param = new HashMap<>();
                    param.put("appid", config.getAppID());
                    param.put("partnerid", response.get("mch_id"));
                    param.put("prepayid", response.get("prepay_id"));
                    param.put("package", "Sign=WXPay");
                    param.put("noncestr", generateNonceStr);
                    param.put("timestamp", currentTimeMillis);
                    param.put("sign", WXPayUtil.generateSignature(param, config.getKey(),
                            WXPayConstants.SignType.MD5));
                    param.put("outtradeno", outTradeNo);
                    return AjaxResult.success("预支付成功", param);
                } else {
                    Map<String, String> param = new HashMap<>();
                    param.put("appid", config.getAppID());
                    param.put("partnerid", response.get("mch_id"));
                    param.put("prepayid", response.get("prepay_id"));
                    param.put("noncestr", generateNonceStr);
                    param.put("timestamp", currentTimeMillis);
                    String stringSignTemp = "appId=" + config.getAppID() + "&nonceStr=" + generateNonceStr + "&package=prepay_id=" + response.get("prepay_id") + "&signType=MD5&timeStamp=" + currentTimeMillis + "" + "&key=" + config.getKey();
                    String sign = MD5Utils.md5Encrypt32Upper(stringSignTemp).toUpperCase();
                    param.put("sign", sign);
                    param.put("outtradeno", outTradeNo);
                    param.put("package", "prepay_id=" + response.get("prepay_id"));//给前端返回的值
                    param.put("mweb_url", response.get("mweb_url"));
                    param.put("trade_type", response.get("trade_type"));
                    param.put("return_msg", response.get("return_msg"));
                    param.put("result_code", response.get("result_code"));
                    param.put("signType", "MD5");
                    return AjaxResult.success("预支付成功", param);
                }
            }
            AssertUtils.isFalse(Boolean.TRUE,response.get("err_code_des"));
        }catch(Exception e){
            e.printStackTrace();
            log.error("微信预支付异常:"+e.getMessage());
            AssertUtils.isFalse(Boolean.TRUE,e.getMessage());
        }
        return AjaxResult.error("获取订单失败");
    }

    @Override
    public String payBack(String resXml, Integer classType) {
        WXConfig config = null;
        try {
            config = new WXConfig();
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.error("进入回调了！！！");
        if (classType == 1) {
            // 微信APPAPPID
            config.setAppId(iSysCommonService.getById(1000004L).getCommonValue());
        } else if (classType == 2) {
            // 微信公众号APPID
            config.setAppId(iSysCommonService.getById(1000055L).getCommonValue());
        } else {
            // 微信小程序APPID
            config.setAppId(iSysCommonService.getById(1000002L).getCommonValue());
        }
        // 微信商户key
        config.setKey(iSysCommonService.getById(1000006L).getCommonValue());
        // 微信商户key
        config.setMchId(iSysCommonService.getById(1000007L).getCommonValue());
        WXPay wxpay = new WXPay(config);
        String xmlBack = "";
        Map<String, String> notifyMap = null;
        try {
            notifyMap = WXPayUtil.xmlToMap(resXml);         // 调用官方SDK转换成map类型数据
            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {//验证签名是否有效，有效则进一步处理
                log.error("验证成功！！！"+ JSON.toJSONString(notifyMap));
                String return_code = notifyMap.get("return_code");//状态
                String outTradeNo = notifyMap.get("out_trade_no");//商户订单号
                String inTradeNo = notifyMap.get("transaction_id");//商户订单号
                String attach = notifyMap.get("attach");// 业务类型
                if (return_code.equals("SUCCESS")) {
                    log.error("验证成功222！！！");
                    if (outTradeNo != null && attach !=null) {
                        /*if("1".equals(attach)){
                            iTbOrderService.notifyShopOrder(outTradeNo,inTradeNo,1);
                        }else if("2".equals(attach)){
                            iTbOrderService.notifyInviteOrder(outTradeNo,inTradeNo,1);
                        }else if("3".equals(attach)){
                            iTbBusinessService.notifyRecharge(outTradeNo,inTradeNo,1);
                        }else if("4".equals(attach)){
                            iTbBusinessService.notifyBuyVip(outTradeNo,inTradeNo,1);
                        }else if("5".equals(attach)){
                            iTbActivityService.notifyActivityEnroll(outTradeNo,inTradeNo,1);
                        }*/
                        // 注意特殊情况：订单已经退款，但收到了支付结果成功的通知，不应把商户的订单状态从退款改成支付成功
                        // 注意特殊情况：微信服务端同样的通知可能会多次发送给商户系统，所以数据持久化之前需要检查是否已经处理过了，处理了直接返回成功标志
                        // 业务数据持久化
                        /*log.error("订单号！！！" + out_trade_no);
                        PayDetails payDetails = payDetailsDao.selectByOrderId(out_trade_no);
                        if (payDetails.getState() == 0) {
                            payDetailsDao.updateState(payDetails.getId(), 1, sdf.format(new Date()), "");
                            if (payDetails.getType() == 1) {
                                //设置查询条件
                                QueryWrapper<PayOrder> queryWrapper = new QueryWrapper<>();
                                //根据订单编号去查询订单
                                queryWrapper.eq("orders_no", out_trade_no);
                                //去订单表中查询到该订单
                                PayOrder orders = payOrderDao.selectOne(queryWrapper);

                                // 改变订单状态
                                orders.setState(1);
                                orders.setPayWay(type);
                                //设置订单更新时间
                                orders.setUpdateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                                payOrderDao.updateById(orders);
                                //调用处理接口
                                userMoneyDao.updateMayMoney(1, orders.getUserId(), orders.getMoney());
                                UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
                                userMoneyDetails.setUserId(orders.getUserId());
                                userMoneyDetails.setTitle("微信充值");
                                userMoneyDetails.setContent("微信充值:" + orders.getPayMoney());
                                userMoneyDetails.setType(1);
                                userMoneyDetails.setMoney(orders.getMoney());
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                userMoneyDetails.setCreateTime(sdf.format(new Date()));
                                userMoneyDetailsService.save(userMoneyDetails);
                            } else if (payDetails.getType() == 2) {
                                Orders orders = ordersDao.selectOne(new QueryWrapper<Orders>().eq("orders_no", payDetails.getOrderId()));
                                UserEntity userEntity = userService.selectUserById(orders.getUserId());
                                UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
                                userMoneyDetails.setMoney(orders.getPayMoney());
                                userMoneyDetails.setUserId(orders.getUserId());
                                userMoneyDetails.setContent("微信支付订单：" + orders.getOrdersNo());
                                userMoneyDetails.setTitle("下单成功");
                                userMoneyDetails.setType(2);
                                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date()));
                                userMoneyDetailsService.save(userMoneyDetails);
                                MessageInfo messageInfo = new MessageInfo();
                                messageInfo.setContent("订单下单成功：" + orders.getOrdersNo());
                                messageInfo.setTitle("订单通知");
                                messageInfo.setState(String.valueOf(4));
                                messageInfo.setUserName(userEntity.getUserName());
                                messageInfo.setUserId(String.valueOf(userEntity.getUserId()));
                                messageInfo.setCreateAt(simpleDateFormat.format(new Date()));
                                messageInfo.setIsSee("0");
                                messageService.saveBody(messageInfo);
                                if (StringUtil.isNotBlank(userEntity.getClientid())) {
                                    userService.pushToSingle(messageInfo.getTitle(), messageInfo.getContent(), userEntity.getClientid());
                                }
                                String userName = userEntity.getUserName();
                                orders.setState("1");
                                orders.setIsRemind(0);
                                orders.setPayWay(2);
                                ordersDao.updateById(orders);
                                OrderTaking byId = orderTakingService.getById(orders.getOrderTakingId());
                                userEntity = userService.selectUserById(byId.getUserId());
                                MessageInfo messageInfos = new MessageInfo();
                                messageInfos.setContent("订单接单成功：" + orders.getOrdersNo());
                                messageInfos.setTitle("订单通知");
                                messageInfos.setState(String.valueOf(4));
                                messageInfos.setUserName(userEntity.getUserName());
                                messageInfos.setUserId(String.valueOf(userEntity.getUserId()));
                                messageInfos.setCreateAt(simpleDateFormat.format(new Date()));
                                messageInfos.setIsSee("0");
                                messageService.saveBody(messageInfos);
                                if (StringUtil.isNotBlank(userEntity.getClientid())) {
                                    userService.pushToSingle(messageInfos.getTitle(), messageInfos.getContent(), userEntity.getClientid());
                                }


                                //小程序订阅号消息推送
                                CommonInfo one = commonInfoService.findOne(235);
                                List<String> msgList = new ArrayList<>();
                                msgList.add(orders.getOrdersNo());//订单号
                                if (byId.getGameId().length() > 15) {
                                    byId.setGameId(byId.getGameId().substring(0, 15) + "...");
                                }
                                msgList.add(byId.getGameId());//商品名称
                                msgList.add(String.valueOf(orders.getOrderNumber()));//商品数量
                                msgList.add(orders.getCreateTime());//下单时间
                                msgList.add(userName);//客户名称
                                if (StringUtils.isNotEmpty(userEntity.getOpenId())) {
                                    SenInfoCheckUtil.sendMsg(userEntity.getShopOpenId(), one.getValue(), null, msgList, 1);
                                }
                            } else {
                                HelpOrder helpOrder = JSONObject.parseObject(payDetails.getRemark(), HelpOrder.class);
                                UserEntity userEntity = userService.selectUserById(helpOrder.getUserId());
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                String date = sdf.format(new Date());
                                helpOrder.setStatus(2);
                                helpOrder.setCreateTime(date);
                                helpOrder.setMoney(helpOrder.getCommission());
                                CommonInfo one = commonInfoService.findOne(120);
                                String value = one.getValue();
                                Double mul = AmountCalUtils.mul(helpOrder.getCommission().doubleValue(), Double.parseDouble(value));
                                BigDecimal sub = AmountCalUtils.sub(helpOrder.getMoney(), BigDecimal.valueOf(mul));
                                helpOrder.setCommission(sub);
                                helpOrder.setPayWay(2);
                                helpOrderDao.insert(helpOrder);

                                UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
                                userMoneyDetails.setUserId(helpOrder.getUserId());
                                userMoneyDetails.setTitle("万能任务");
                                userMoneyDetails.setContent("万能任务微信支付扣款：" + helpOrder.getMoney());
                                userMoneyDetails.setType(2);
                                userMoneyDetails.setMoney(helpOrder.getMoney());
                                userMoneyDetails.setCreateTime(date);
                                userMoneyDetailsService.save(userMoneyDetails);
                                if (userEntity.getClientid() != null) {
                                    userService.pushToSingle("派发订单", "您的订单已经派发成功！", userEntity.getClientid());
                                }
                                MessageInfo messageInfo = new MessageInfo();
                                messageInfo.setContent("您的订单已经派发成功！");
                                messageInfo.setTitle("订单通知");
                                messageInfo.setState(String.valueOf(5));
                                messageInfo.setUserName(userEntity.getUserName());
                                messageInfo.setUserId(String.valueOf(userEntity.getUserId()));
                                messageService.saveBody(messageInfo);
                            }
                        }*/
                        System.err.println("微信手机支付回调成功订单号:" + outTradeNo + "");
                        xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    } else {
                        System.err.println("微信手机支付回调成功订单号:" + outTradeNo + "");
                        xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                    }
                } else {
                }
                return xmlBack;
            } else {
                // 签名错误，如果数据里没有sign字段，也认为是签名错误
                System.err.println("手机支付回调通知签名错误");
                xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                return xmlBack;
            }
        } catch (
                Exception e) {
            System.err.println("手机支付回调通知失败" + e);
            xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        return xmlBack;
    }

    public String getGeneralOrder() {
        Date date = new Date();
        String newString = String.format("%0" + 4 + "d", (int) ((Math.random() * 9 + 1) * 1000));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String format = sdf.format(date);
        return format + newString;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean refund(String orderNumber, BigDecimal money) {
        WXConfigUtil config = null;
        try {
            config = new WXConfigUtil();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Long commInfoId = 0L;
        // 1 app微信 2微信公众号 3 微信小程序 todo
        Integer payWay = 1;
        switch (payWay) {
            case 1:
                // appId
                commInfoId = 1000004L;
                break;
            case 2:
                // 公众号id
                commInfoId = 1000055L;
                break;
            case 3:
                // 小程序id
                commInfoId = 1000002L;
                break;
        }
        config.setAppId(iSysCommonService.getById(commInfoId).getCommonValue());
        // 微信商户key
        config.setKey(iSysCommonService.getById(1000006L).getCommonValue());
        // 微信商户号mchId
        config.setMchId(iSysCommonService.getById(1000007L).getCommonValue());
        WXPay wxpay = new WXPay(config);
        Map<String, String> data = new HashMap<>();
        data.put("appid", config.getAppID());
        data.put("mch_id", config.getMchID());
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        try {
            data.put("sign", WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.MD5));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        // 订单号,支付单号一致
        data.put("out_trade_no", orderNumber);
        // 退款单号，同一笔用不同的退款单号
        data.put("out_refund_no", orderNumber);
        BigDecimal multiply = money.multiply(BigDecimal.valueOf(100));
        String fee = String.valueOf(multiply.intValue());
        // 1块等于微信支付传入100); 支付总额
        data.put("total_fee", fee);
        // 1块等于微信支付传入100); 退款总额
        data.put("refund_fee", fee);
        // 使用官方API退款
        try {
            Map<String, String> response = wxpay.refund(data);
            if ("SUCCESS".equals(response.get("return_code"))) {
                // 主要返回以下5个参数
                System.err.println("退款成功");
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            log.info("微信退款异常：" + e.getMessage(), e);
            e.printStackTrace();
            return false;
        }
    }
}